package com.example.springboot.context;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.Configuration;

/**
 * 继承了 {@link BeanFactoryPostProcessor} ，但比它更早执行。
 * <p> <b> 在 BeanDefinition 已经注册, 但 Bean 还没实例化之前 </b>
 *
 * <p> 场景：允许开发者动态注册、修改 Bean 定义，可以加载classpath之外的bean
 * <p> 1. 动态注册 Bean, 比如根据配置文件决定要不要加载某些 Bean
 * <p> 2. 框架扩展, MyBatis、Spring Data JPA 等都用 BeanDefinitionRegistryPostProcessor 动态扫描接口，注册代理类的 BeanDefinition
 * <p> 3. 条件化 Bean 注册, 在 @Conditional 之前，还可以自己写逻辑动态注册
 *
 * <p> <i> Configuration 中的 proxyBeanMethods : 是否使用动态代理。 选择false,无代理，性能好 </i>
 *
 * <p>
 *
 * @author Zhang.Z
 * @version 2025-09-21
 * @see Test3BeanFactoryPostProcessor
 */
@Configuration(proxyBeanMethods = false)
public class Test2BeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {


    /**
     * {@link BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry } 方法
     * <p> 先于 {@link #postProcessBeanFactory } 方法执行
     * <p> 1. 可以直接操作 BeanDefinitionRegistry（增删改 BeanDefinition）
     * <p> 2. 常用于动态注册 Bean（比如 MyBatis、Spring Cloud 里的自动配置）
     * <p>
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("test2 bean registry");
        // 动态注册一个 Bean

        /**
         * GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
         * beanDefinition.setBeanClass(MyService.class);
         * beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
         * registry.registerBeanDefinition("myService", beanDefinition);
         */
    }

    /*--- BeanFactoryPostProcessor 的方法 ---*/

    /**
     * {@link BeanFactoryPostProcessor#postProcessBeanFactory } 方法
     * <p>可以拿到 ConfigurableListableBeanFactory，修改已有的 BeanDefinition（比如改 scope、改属性）
     * <p> <i> 注意：这里不能再新增 BeanDefinition，只能改 </i>
     *
     * <p> 此方法在BeanDefinitionRegistryPostProcessor的实现类中重写后，
     * 会先于 BeanFactoryPostProcessor 实现类执行
     * <p>
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("test2 bean registry factory");
    }
}
